﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;


namespace Autofocus
{
    public partial class Form1 : Form
    {
        MotiCam My_MotiCam;
        IntPtr[] hCameraList;
        Stepper My_Stepper;
        Int32 X_sml = 8;
        Int32 X_med = 80;
        Int32 X_lrg = 2000;
        Int32 Y_sml = 1;
        Int32 Y_med = 2;
        Int32 Y_lrg = 80;
        Int32 Z_sml = 40;
        Int32 Z_med = 80;
        Int32 Z_lrg = 400;

       


        #region Motor Controls

        private void btn_X_fwd_sml_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveX(X_sml);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }         
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_X_fwd_med_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveX(X_med);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_X_fwd_lrg_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveX(X_lrg);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_X_back_sml_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveX(-X_sml);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_X_back_med_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveX(-X_med);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_X_back_lrg_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveX(-X_lrg);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Y_fwd_sml_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveY(Y_sml);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Y_fwd_med_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveY(Y_med);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Y_fwd_lrg_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveY(Y_lrg);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Y_back_sml_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveY(-Y_sml);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Y_back_med_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveY(-Y_med);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Y_back_lrg_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveY(-Y_lrg);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(2000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Z_fwd_sml_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveZ(Z_sml);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(1000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Z_fwd_med_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveZ(Z_med);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(1000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Z_fwd_lrg_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveZ(Z_lrg);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(1000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Z_back_sml_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveZ(-Z_sml);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(1000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Z_back_med_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveZ(-Z_med);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(1000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }

        private void btn_Z_back_lrg_Click(object sender, EventArgs e)
        {
            int n = My_Stepper.MoveZ(-Z_lrg);

            if (n == 0)
            {
                if (checkBox_Update_Image.Checked)
                {
                    System.Threading.Thread.Sleep(1000);
                    Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
                    imageBox1.Image = img;
                }
            }
            else if (n == 1)
            {
                MessageBox.Show("Timed out waiting for motor. Is it connected?");
            }
            else if (n == 2)
            {
                MessageBox.Show("Limit switch hit! Turn off power and manually correct...");
            }
        }


        #endregion


        #region Image Proc Functions

        Image<Bgr, Byte> GetImage(MotiCam camera, Int32 binningIndex)
        {
            if (camera != null)
            {
                Byte[] buffer = new Byte[camera.m_pWidth[binningIndex] * camera.m_pHeight[binningIndex] * camera.m_bitDepth * camera.m_colorChannel / 8];
                camera.GetFrame(ref buffer);
                Image<Bgr, Byte> img = new Image<Bgr, Byte>(camera.m_pWidth[binningIndex], camera.m_pHeight[binningIndex]);

                GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                IntPtr imageHeaderForBytes = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MIplImage)));
                CvInvoke.cvInitImageHeader(imageHeaderForBytes, new System.Drawing.Size(camera.m_pWidth[binningIndex], camera.m_pHeight[binningIndex]), Image<Bgr, Byte>.CvDepth, camera.m_colorChannel, 0, 4); // align
                Marshal.WriteIntPtr(imageHeaderForBytes, (int)Marshal.OffsetOf(typeof(MIplImage), "imageData"), handle.AddrOfPinnedObject());
                CvInvoke.cvCopy(imageHeaderForBytes, img, IntPtr.Zero);

                Marshal.FreeHGlobal(imageHeaderForBytes);
                handle.Free();
                return img;
            }

            Image<Bgr, Byte> temp = new Image<Bgr, byte>(400, 200, new Bgr(255, 0, 0)); //Create an image of 400x200 of Blue color
            MCvFont f = new MCvFont(FONT.CV_FONT_HERSHEY_COMPLEX, 1.0, 1.0); //Create the font

            temp.Draw("No camera connected!", ref f, new System.Drawing.Point(10, 80), new Bgr(0, 255, 0)); //Draw message on the image using the specific font
            return temp;
        }

        private Double Get_Avg_Val(Image<Bgr, Byte> current_image, double threshold)
        {
            // This function returns the average value of the image after binary thresholding at the given threshold
            Image<Gray, float> Gray_current_image = current_image.Convert<Gray, float>();
            Gray hist_threshold = new Gray(threshold);
            Gray max_value = new Gray(255);
            Gray_current_image._ThresholdBinary(hist_threshold, max_value);
            //imageBox2.Image = Gray_current_image; 
            Gray My_Gray;
            MCvScalar My_MCvScalar;
            Gray_current_image.AvgSdv(out My_Gray, out My_MCvScalar);
            return My_Gray.Intensity;
        }

        private Double Calculate_Focus(Image<Bgr, Byte> img_1)
        {
            Double focus_value;
            Image<Gray, float> img_2 = img_1.Convert<Gray, float>().Sobel(1, 1, 3);
            Image<Gray, float> My_Processed_Image = img_2.Pow(2);
            Gray My_Gray;
            MCvScalar My_MCvScalar;
            My_Processed_Image.AvgSdv(out My_Gray, out My_MCvScalar);
            focus_value = My_Gray.Intensity;
            return focus_value;
        }

        #endregion Image Proc Functions



        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Find Cameras and populate combo-box
            IntPtr hCameraHandle;
            hCameraList = new IntPtr[10];
            Int32 indx = 0;
            try
            {
                hCameraHandle = Motic.MUCam_findCamera();
                while (hCameraHandle != IntPtr.Zero)
                {
                    hCameraList[indx++] = hCameraHandle;
                    comboBox_Cameras.Items.Add(Motic.GetType(hCameraHandle));
                    hCameraHandle = Motic.MUCam_findCamera();
                }
                if (comboBox_Cameras.Items.Count > 0)
                {
                    comboBox_Cameras.SelectedIndex = 0;
                }
            }
            catch
            {
                MessageBox.Show("Unable to find any connected cameras!");
            }

            // Connect to Stepper Motor
            My_Stepper = new Stepper();
            My_Stepper.Connect(textBox_SP_name.Text, 9600);

        }

       

        private Boolean Auto_Focus(Int32 stops, Int32 step)
        {
            Double[] focus_values = new Double[stops];
            Image<Bgr, Byte>[] img_array = new Image<Bgr, byte>[stops];

            // Get series of images and find the focus value for each
            My_Stepper.MoveZ((step * stops * -1) / 2);

            System.Threading.Thread.Sleep(1500);
            for (int i = 0; i < stops; i++)
            {
                img_array[i] = GetImage(My_MotiCam, 0);
                focus_values[i] = Calculate_Focus(img_array[i]);
               
                // If focus has got worse two steps in a row
                if (i > 1)
                {
                    if ((focus_values[i] < focus_values[i - 1]) && (focus_values[i - 1] < focus_values[i - 2]))
                    {
                        My_Stepper.MoveZ(-2 * step);
                        // Picture in focus
                        return true;
                    }
                }

                // Move to new position and wait for camera to acquire a new buffer
                My_Stepper.MoveZ(step);
                System.Threading.Thread.Sleep(1500);
            }
            return false;
        }


        // Delegate to to perform async call to capture_sequence and create worker thread
        delegate void CapSeqDelegate(Int32 num_images, String file_name, Int32 file_start_index, Int32 min_delta_X, Int32 X_Step, Int32 Y_Step, Int32 Y_pos_high_limit, Int32 Y_pos_low_limit, Int32 afc_step, Int32 afc_stops, Double afc_threshold);

        // Delegate to update the UI (called synchronously from the worker thread)
        delegate void ShowProgressHandler(object sender, ShowProgressArgs e);

        class ShowProgressArgs : EventArgs
        {
            // EventArgs class to pass data between main and worker threads
            public Boolean cancel;
            public Int32 images_done;
            public Int32 num_images;
            public Int32 interface_pos;
            public Image<Bgr, Byte> img_1, img_2;
            public String current_action;

            public ShowProgressArgs(Int32 num_images)
            {
                this.images_done = 0;
                this.num_images = num_images;
                this.interface_pos = 0;
            }
        }
        
        enum CalcState
        { 
            Pending,
            Working,
            Cancelled,
        }
        CalcState state = CalcState.Pending;

        void ShowProgress(object sender, ShowProgressArgs e)
        { 
            // Make sure we're on the right thread
            if (this.InvokeRequired == false)
            {
                // Update the UI
                toolStripProgressBar1.Value = (Int32)Math.Floor((double)e.images_done / (double)e.num_images * 100);
                label_current_image.Text = e.images_done.ToString() + " of " + e.num_images.ToString() + " images done.";
                label_current_action.Text = e.current_action;
                label_interface_position.Text = "Interface Position: " + e.interface_pos.ToString();
                imageBox1.Image = e.img_2;
                imageBox2.Image = e.img_1;
                imageBox1.Refresh();
                imageBox2.Refresh();
                // Check for cancel
                e.cancel = (state == CalcState.Cancelled);

                // Check for completion
                if (e.cancel == true || e.images_done == e.num_images)
                {
                    state = CalcState.Pending;
                    btn_Cap_Seq.Text = "Capture Sequence";
                    btn_Cap_Seq.Enabled = true;
                    toolStripStatusLabel1.Text = "Pending...";
                    toolStripProgressBar1.Value = 0;
                }
            }
            else // Transfer control to the correct thread
            {
                ShowProgressHandler showProgress = new ShowProgressHandler(ShowProgress);
                Invoke(showProgress, new object[] { sender, e });
            }
        
        }

        private void capture_sequence(Int32 num_images, String file_name, Int32 file_start_index, Int32 min_delta_X, Int32 X_Step, Int32 Y_Step, Int32 Y_pos_high_limit, Int32 Y_pos_low_limit, Int32 afc_step, Int32 afc_stops, Double afc_threshold)
        {
            object sender = System.Threading.Thread.CurrentThread;
            ShowProgressArgs e = new ShowProgressArgs(num_images);
            Image<Bgr, Byte> img_1;
            Image<Bgr, Byte> img_2;
            Int32 delta_X = 0, delta_Y = 0, cumulative_X = 0, cumulative_Y = 0;
            Int32 counter = 0;

            // Take and save first image in sequence
            System.Threading.Thread.Sleep(2000);
            img_1 = GetImage(My_MotiCam, 0);
            img_2 = img_1;
            img_1.Save(file_name + "img_" + String.Format("{0:000}", (file_start_index)) + ".tiff");
            using (StreamWriter w = File.AppendText(file_name + "TileConfig.txt"))
            {
                w.WriteLine("dim = 2");
                w.WriteLine(file_name.Substring(file_name.Length-3) + "img_001.tiff; ; (0.0, 0.0)");
            }
            e.images_done = 1;
            e.img_1 = img_1;
            e.img_2 = img_2;
            ShowProgress(sender, e);
            if (e.cancel) return;

            for (int j = 0; j < num_images-1; j++)
            {
                #region MOVE IN THE X DIRECTION
                counter = 0;
                while (Math.Abs(delta_X) < Math.Abs(min_delta_X))
                {
                    if (counter > 9)
                    {
                        MessageBox.Show("Tried to move 10 times in X direction, could not find shift. Aborting...");
                        e.images_done = num_images;
                        ShowProgress(sender, e);
                        return;
                    }

                    // Move in X direction a certain amount
                    My_Stepper.MoveX(X_Step);

                    // Take a new picture
                    System.Threading.Thread.Sleep(2000);
                    img_2 = GetImage(My_MotiCam, 0);

                    // Obtain position correlation
                    Phase.Calc_Phase_Correlation(img_1.Convert<Gray, float>(), img_2.Convert<Gray, float>(), ref delta_X, ref delta_Y);
                    counter++;
                    
                    // Update the UI
                    e.img_2 = img_2;
                    e.current_action = "Moving in the X direction attempt " + counter.ToString() + "/9. Delta_X: " + delta_X.ToString() + " Delta_Y: " + delta_Y.ToString();
                    ShowProgress(sender, e);
                    if (e.cancel) return;
                }
                e.current_action = "X position OK...";
                ShowProgress(sender, e);
                if (e.cancel) return;
                delta_X = 0;
                delta_Y = 0;
                #endregion MOVE IN THE X DIRECTION

                #region ADJUST Y POSITION
                counter = 0;
                while (counter < 15)
                {                                                           
                    if (counter == 14)
                    {
                        MessageBox.Show("Tried adjust 15 times in Y direction but unable to centre coating. Aborting...");
                        e.images_done = num_images;
                        ShowProgress(sender, e);
                        return;
                    }
                    System.Threading.Thread.Sleep(2000);
                    img_2 = GetImage(My_MotiCam, 0);

                    Int32 interface_position = Find_Interface(ref img_2);
                    e.interface_pos = interface_position;
                    e.img_2 = img_2;
                    if (interface_position < (Y_pos_high_limit * img_2.Size.Height / 100))
                    {
                        e.current_action = "Moving in the -Y direction attempt " + counter.ToString() + "/15.";
                        ShowProgress(sender, e);
                        if (e.cancel) return;
                        My_Stepper.MoveY(-Y_Step);
                        counter++;
                    }
                    else if (interface_position > (Y_pos_low_limit * img_2.Size.Height / 100))
                    {
                        e.current_action = "Moving in the +Y direction attempt " + counter.ToString() + "/15.";
                        ShowProgress(sender, e);
                        if (e.cancel) return;
                        My_Stepper.MoveY(Y_Step);
                        counter++;
                    }
                    else
                    {
                        // Position is ok
                        e.current_action = "Y Position OK.";
                        ShowProgress(sender, e);
                        if (e.cancel) return;
                        break;
                    }
                }
                #endregion ADJUST Y POSITION

                #region AUTOFOCUS
                if (Calculate_Focus(img_2) < afc_threshold || (j % 3) == 0)
                {
                    e.current_action = "Autofocusing...";
                    ShowProgress(sender, e);
                    if (e.cancel) return;
                    Auto_Focus(afc_stops, afc_step);
                    System.Threading.Thread.Sleep(2000);
                    img_2 = GetImage(My_MotiCam, 0);
                    e.img_2 = img_2;
                    e.current_action = "Autofocusing...Done...";
                    ShowProgress(sender, e);
                    if (e.cancel) return;
                }
                #endregion AUTOFOCUS

                // SAVE NEW IMAGE AND UPDATE UI
                System.Threading.Thread.Sleep(2000);
                img_2 = GetImage(My_MotiCam, 0);
                img_2.Save(file_name + "img_" + String.Format("{0:000}", (j + file_start_index +1)) + ".tiff");

                // Calculate the position correlation of img_2 relative to img_1 and record the cumulative shift in the TileConfig file
                Phase.Calc_Phase_Correlation(img_1.Convert<Gray, float>(), img_2.Convert<Gray, float>(), ref delta_X, ref delta_Y);
                cumulative_X -= delta_X;
                cumulative_Y -= delta_Y;
                delta_X = 0;
                delta_Y = 0;
                using (StreamWriter w = File.AppendText(file_name + "TileConfig.txt"))
                {
                    w.WriteLine(file_name.Substring(file_name.Length - 3) + "img_" + String.Format("{0:000}", j + 2) + ".tiff; ; (" + cumulative_X.ToString() + ", " + cumulative_Y.ToString() + ")");
                }
                img_1 = img_2;
                e.img_1 = img_2;

                // SHOW PROGRESS (checking for cancel and completion)
                e.images_done++;
                ShowProgress(sender, e);
                if (e.cancel) break;
            }
        }


        private void btn_Cap_Seq_Click(object sender, EventArgs e)
        {
            Int32 num_images = Convert.ToInt32(nud_no_images.Value);
            String file_name = textBox_file_name.Text;
            Int32 file_start_index = Convert.ToInt32(nud_file_start_index.Value);
            Int32 min_delta_x = Convert.ToInt32(nud_min_delta_X.Value);
            Int32 min_delta_X = Convert.ToInt32(nud_min_delta_X.Value);
            Int32 X_Step = Convert.ToInt32(nud_X_motor_step_size.Value);
            Int32 Y_Step = Convert.ToInt32(nud_Y_motor_step_size.Value);
            Int32 Y_Pos_high_limit = Convert.ToInt32(nud_Y_pos_high_limit.Value);
            Int32 Y_Pos_low_limit = Convert.ToInt32(nud_Y_pos_low_limit.Value);
            Int32 stops = Convert.ToInt32(nud_afc_Stops.Value);
            Int32 step = Convert.ToInt32(nud_afc_StepSz.Value);
            Double afc_threshold = Convert.ToDouble(nud_afc_threshold.Value);


            switch (state)
            {
                // Start working and allow cancelling
                case CalcState.Pending:
                    state = CalcState.Working;
                    btn_Cap_Seq.Text = "Cancel";
                    toolStripStatusLabel1.Text = "Working...";

                    // Async delegate method
                    CapSeqDelegate CapSeq = new CapSeqDelegate(capture_sequence);
                    CapSeq.BeginInvoke(num_images, file_name, file_start_index, min_delta_X, X_Step, Y_Step, Y_Pos_high_limit, Y_Pos_low_limit, step, stops, afc_threshold, null, null);
                    break;

                // Cancel working 
                case CalcState.Working:
                    state = CalcState.Cancelled;
                    toolStripStatusLabel1.Text = "Cancelled...";
                    btn_Cap_Seq.Enabled = false;
                    break;

                // Shouldn't be able to press button while it is cancelling
                case CalcState.Cancelled:
                    Debug.Assert(false);
                    break;
            }
        }


        private Int32 Find_Interface(ref Image<Bgr, Byte> img_1)
        {
            Int32 interface_position;
            // Create patch
            Image<Gray, float> img_cross_corr;
            Int32 patch_X = img_1.Size.Width;
            Int32 patch_Y = (Int32)Math.Floor(0.4 * img_1.Size.Height);
            Image<Bgr, Byte> patch = new Image<Bgr, byte>(patch_X, patch_Y, new Bgr(255, 255, 255));
            patch.Draw(new Rectangle(0, 0, patch_X, (Int32)Math.Floor(0.5 * patch_Y)), new Bgr(0, 0, 0), 0);

            img_cross_corr = img_1.MatchTemplate(patch, Emgu.CV.CvEnum.TM_TYPE.CV_TM_SQDIFF);

            double[] minVal;
            double[] maxVal;
            System.Drawing.Point[] minLoc;
            System.Drawing.Point[] maxLoc;
            img_cross_corr.MinMax(out minVal, out maxVal, out minLoc, out maxLoc);
            interface_position = minLoc[0].Y + (Int32)Math.Floor(0.5 * patch_Y);
            img_1.Draw(new Rectangle(0, interface_position, img_1.Size.Width, 10), new Bgr(255, 0, 0), 0);
            return interface_position;
        }


        private void button_Calc_Histogram_Click(object sender, EventArgs e)
        {
            // Calculate and display the histogram for the current image to aid in threshold selection
            // Then display average value after thresholding at set threshold
            Image<Bgr, Byte> current_image = new Image<Bgr,byte>(imageBox1.Image.Bitmap);
            Image<Gray, float> Gray_current_image = current_image.Convert<Gray, float>();
            histogramBox1.ClearHistogram();
            histogramBox1.GenerateHistograms(Gray_current_image, 255);
            histogramBox1.Refresh();
        }

        private void button_Autofocus_Click(object sender, EventArgs e)
        {
            Int32 stops = Convert.ToInt32(nud_afc_Stops.Value);
            Int32 step = Convert.ToInt32(nud_afc_StepSz.Value);
            Image<Bgr, Byte> img = GetImage(My_MotiCam, 0);
            imageBox2.Image = img;
            imageBox2.Refresh();

            Auto_Focus(stops, step);

            img = GetImage(My_MotiCam, 0);
            imageBox1.Image = img;
        }

        private void btn_cpy_across_Click(object sender, EventArgs e)
        {
            imageBox2.Image = imageBox1.Image;
        }

        private void btn_Phase_Corr_Click(object sender, EventArgs e)
        {
            // Current image
            Image<Bgr, Byte> Image_1 = new Image<Bgr, byte>(imageBox1.Image.Bitmap);
            // Previous image
            Image<Bgr, Byte> Image_2 = new Image<Bgr, byte>(imageBox2.Image.Bitmap);

            Image<Gray, float> img_1 = Image_1.Convert<Gray, float>();
            Image<Gray, float> img_2 = Image_2.Convert<Gray, float>();

            imageBox1.Image = img_1;
            imageBox2.Image = img_2;

            Int32 delta_X = 0, delta_Y = 0;
            Phase.Calc_Phase_Correlation(img_1, img_2, ref delta_X, ref delta_Y);

            label_phase_corr.Text = "Delta_X: " + delta_X.ToString() + " Delta_Y: " + delta_Y.ToString();
        }

        private void btn_Find_Interface_Click(object sender, EventArgs e)
        {
            Int32 Y_Pos = 0;
            Image<Bgr, Byte> img_1 = new Image<Bgr, byte>(imageBox1.Image.Bitmap);

            Y_Pos = Find_Interface(ref img_1);

            imageBox1.Image = img_1;
            label_interface_position.Text = "Interface Position: " + Y_Pos.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Image<Bgr, Byte> img_1 = new Image<Bgr, byte>(imageBox1.Image.Bitmap);
            lbl_current_focus_score.Text = Calculate_Focus(img_1).ToString();
        }

       

    }
}
